package com.qsw.fileoperatelib.zip;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 压缩文件工具类
 */
public class ZipUtil {
    private static final int BUFFER = 4096;

    /**
     * 压缩文件和文件夹
     *
     * @param srcFilePath    要压缩的文件或文件夹路径
     * @param dstZipFilePath 压缩完成的Zip文件路径
     * @param deleteIfExits  true：若目标压缩文件存在则删除重建；false：若目标压缩文件存在则返回不操作
     * @throws IOException 文件操作异常
     */
    public static void zip(String srcFilePath, String dstZipFilePath, boolean deleteIfExits) throws IOException {
        File dstZipFile = new File(dstZipFilePath);
        if (dstZipFile.exists() && dstZipFile.isFile()) {
            if (deleteIfExits) {
                dstZipFile.delete();
            } else {
                return;
            }
        }
        dstZipFile.createNewFile();

        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dstZipFilePath));
        File srcFile = new File(srcFilePath);
        processZip(srcFile.getAbsolutePath(), srcFile.getName(), zos);
        zos.finish();
        zos.close();
    }

    /**
     * 压缩文件和文件夹
     *
     * @param srcFilePath    要压缩的文件或文件夹路径
     * @param dstFilePath    要压缩的文件或文件夹在压缩文件中的路径
     * @param zipOutputSteam 压缩文件输出流
     * @throws IOException 文件操作异常
     */
    private static void processZip(String srcFilePath, String dstFilePath, ZipOutputStream zipOutputSteam) throws IOException {
        if (zipOutputSteam == null) {
            return;
        }
        File srcFile = new File(srcFilePath);
        if (srcFile.isFile()) {
            ZipEntry zipEntry = new ZipEntry(dstFilePath);
            zipOutputSteam.putNextEntry(zipEntry); // 在压缩文件中创建一个文件
            FileInputStream fis = new FileInputStream(srcFile);
            int len;
            byte[] buffer = new byte[BUFFER];
            while ((len = fis.read(buffer, 0, BUFFER)) > 0) {
                zipOutputSteam.write(buffer, 0, len);
            }
            zipOutputSteam.closeEntry();
            fis.close();
        } else {
            String[] fileList = srcFile.list();

            ZipEntry zipEntry = new ZipEntry(dstFilePath + File.separator);
            zipOutputSteam.putNextEntry(zipEntry); // 在压缩文件中创建一个文件夹
            zipOutputSteam.closeEntry();

            for (String fileName : fileList) {
                processZip(srcFilePath + File.separator + fileName, dstFilePath + File.separator + fileName, zipOutputSteam);
            }
        }
    }

    /**
     * 解压文件
     *
     * @param zipFile   zip文件路径
     * @param targetDir 解压到的目标位置
     * @throws IOException 文件操作异常
     */
    public static void unzip(String zipFile, String targetDir) throws IOException {
        File dstFolder = new File(targetDir);
        if (!dstFolder.exists() || !dstFolder.isDirectory()) {
            dstFolder.mkdirs();
        }

        BufferedOutputStream bos;
        ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
        ZipEntry zipEntry;
        while ((zipEntry = zis.getNextEntry()) != null) {
            File dstFile = new File(targetDir + File.separator + zipEntry.getName());
            if (zipEntry.isDirectory()) {
                if (!dstFile.exists()) {
                    dstFile.mkdirs();
                }
                continue;
            }

            File dstParentFolder = new File(dstFile.getParent());
            if (!dstParentFolder.exists()) {
                dstParentFolder.mkdirs();
            }

            bos = new BufferedOutputStream(new FileOutputStream(dstFile), BUFFER);

            int count;
            byte[] buffer = new byte[BUFFER];
            while ((count = zis.read(buffer, 0, BUFFER)) > 0) {
                bos.write(buffer, 0, count);
            }
            bos.flush();
            bos.close();
        }
        zis.close();
    }
}